namespace XEAS.Framework.ShellLib
{
    using System;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;

    public class ShellBrowseForFolderDialog
    {
        public BrowseInfoFlag DetailsFlags = (BrowseInfoFlag.BIF_SHAREABLE | BrowseInfoFlag.BIF_BROWSEINCLUDEFILES | BrowseInfoFlag.BIF_USENEWUI | BrowseInfoFlag.BIF_VALIDATE | BrowseInfoFlag.BIF_STATUSTEXT);
        public IntPtr hwndOwner = IntPtr.Zero;
        private string m_DisplayName = "";
        private string m_FullName = "";
        public string RootPath = "";
        public ShellApi.CSIDL RootSpecialFolder = ShellApi.CSIDL.CSIDL_DESKTOP;
        public RootTypeOptions RootType = RootTypeOptions.BySpecialFolder;
        public string Title = "";
        public IntPtr UserToken = IntPtr.Zero;

        public event InitializedHandler OnInitialized;

        public event IUnknownHandler OnIUnknown;

        public event SelChangedHandler OnSelChanged;

        public event ValidateFailedHandler OnValidateFailed;

        public void EnableOk(IntPtr hwnd, bool Enabled)
        {
            SendMessage(hwnd, 0x465, 0, Enabled ? 1 : 0);
        }

        private int myBrowseCallbackProc(IntPtr hwnd, uint uMsg, int lParam, int lpData)
        {
            string str;
            ValidateFailedEventArgs args;
            switch (((BrowseForFolderMessages) uMsg))
            {
                case BrowseForFolderMessages.BFFM_INITIALIZED:
                    Debug.WriteLine("BFFM_INITIALIZED");
                    if (this.OnInitialized != null)
                    {
                        InitializedEventArgs args2 = new InitializedEventArgs(hwnd);
                        this.OnInitialized(this, args2);
                    }
                    break;

                case BrowseForFolderMessages.BFFM_SELCHANGED:
                    Debug.WriteLine("BFFM_SELCHANGED");
                    if (this.OnSelChanged != null)
                    {
                        SelChangedEventArgs args3 = new SelChangedEventArgs(hwnd, (IntPtr) lParam);
                        this.OnSelChanged(this, args3);
                    }
                    break;

                case BrowseForFolderMessages.BFFM_VALIDATEFAILEDA:
                    Debug.WriteLine("BFFM_VALIDATEFAILEDA");
                    if (this.OnValidateFailed != null)
                    {
                        str = Marshal.PtrToStringAnsi((IntPtr) lParam);
                        args = new ValidateFailedEventArgs(hwnd, str);
                        return this.OnValidateFailed(this, args);
                    }
                    break;

                case BrowseForFolderMessages.BFFM_VALIDATEFAILEDW:
                    Debug.WriteLine("BFFM_VALIDATEFAILEDW");
                    if (this.OnValidateFailed != null)
                    {
                        str = Marshal.PtrToStringUni((IntPtr) lParam);
                        args = new ValidateFailedEventArgs(hwnd, str);
                        return this.OnValidateFailed(this, args);
                    }
                    break;

                case BrowseForFolderMessages.BFFM_IUNKNOWN:
                    Debug.WriteLine("BFFM_IUNKNOWN");
                    if (this.OnIUnknown != null)
                    {
                        IUnknownEventArgs args4 = new IUnknownEventArgs(hwnd, (IntPtr) lParam);
                        this.OnIUnknown(this, args4);
                    }
                    break;
            }
            return 0;
        }

        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, int lParam);
        [DllImport("User32.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint Msg, uint wParam, [MarshalAs(UnmanagedType.LPWStr)] string lParam);
        public void SetExpanded(IntPtr hwnd, string path)
        {
            SendMessage(hwnd, 0x46a, 1, path);
        }

        public void SetOkText(IntPtr hwnd, string text)
        {
            SendMessage(hwnd, 0x469, 0, text);
        }

        public void SetSelection(IntPtr hwnd, string path)
        {
            SendMessage(hwnd, 0x467, 1, path);
        }

        public void SetStatusText(IntPtr hwnd, string text)
        {
            SendMessage(hwnd, 0x468, 1, text);
        }

        public void ShowDialog()
        {
            IntPtr ptr;
            ShellApi.STRRET strret;
            string str;
            this.m_FullName = "";
            this.m_DisplayName = "";
            IMalloc o = ShellFunctions.GetMalloc();
            if (this.RootType == RootTypeOptions.BySpecialFolder)
            {
                ShellApi.SHGetFolderLocation(this.hwndOwner, (int) this.RootSpecialFolder, this.UserToken, 0, out ptr);
            }
            else
            {
                uint num;
                ShellApi.SHParseDisplayName(this.RootPath, IntPtr.Zero, out ptr, 0, out num);
            }
            ShellApi.BROWSEINFO lbpi = new ShellApi.BROWSEINFO();
            lbpi.hwndOwner = this.hwndOwner;
            lbpi.pidlRoot = ptr;
            lbpi.pszDisplayName = new string(' ', 0x100);
            lbpi.lpszTitle = this.Title;
            lbpi.ulFlags = (uint) this.DetailsFlags;
            lbpi.lParam = 0;
            lbpi.lpfn = new ShellApi.BrowseCallbackProc(this.myBrowseCallbackProc);
            IntPtr pidl = ShellApi.SHBrowseForFolder(ref lbpi);
            this.m_DisplayName = lbpi.pszDisplayName;
            IShellFolder desktopFolder = ShellFunctions.GetDesktopFolder();
            desktopFolder.GetDisplayNameOf(pidl, 0x8000, out strret);
            ShellApi.StrRetToBSTR(ref strret, ptr, out str);
            this.m_FullName = str;
            if (ptr != IntPtr.Zero)
            {
                o.Free(ptr);
            }
            if (pidl != IntPtr.Zero)
            {
                o.Free(pidl);
            }
            Marshal.ReleaseComObject(desktopFolder);
            Marshal.ReleaseComObject(o);
        }

        public string DisplayName
        {
            get
            {
                return this.m_DisplayName;
            }
        }

        public string FullName
        {
            get
            {
                return this.m_FullName;
            }
        }

        public enum BrowseForFolderMessages
        {
            BFFM_ENABLEOK = 0x465,
            BFFM_INITIALIZED = 1,
            BFFM_IUNKNOWN = 5,
            BFFM_SELCHANGED = 2,
            BFFM_SETEXPANDED = 0x46a,
            BFFM_SETOKTEXT = 0x469,
            BFFM_SETSELECTIONA = 0x466,
            BFFM_SETSELECTIONW = 0x467,
            BFFM_SETSTATUSTEXTA = 0x464,
            BFFM_SETSTATUSTEXTW = 0x468,
            BFFM_VALIDATEFAILEDA = 3,
            BFFM_VALIDATEFAILEDW = 4
        }

        [Flags]
        public enum BrowseInfoFlag
        {
            BIF_BROWSEFORCOMPUTER = 0x1000,
            BIF_BROWSEFORPRINTER = 0x2000,
            BIF_BROWSEINCLUDEFILES = 0x4000,
            BIF_BROWSEINCLUDEURLS = 0x80,
            BIF_DONTGOBELOWDOMAIN = 2,
            BIF_EDITBOX = 0x10,
            BIF_NEWDIALOGSTYLE = 0x40,
            BIF_NONEWFOLDERBUTTON = 0x200,
            BIF_NOTRANSLATETARGETS = 0x400,
            BIF_RETURNFSANCESTORS = 8,
            BIF_RETURNONLYFSDIRS = 1,
            BIF_SHAREABLE = 0x8000,
            BIF_STATUSTEXT = 4,
            BIF_UAHINT = 0x100,
            BIF_USENEWUI = 80,
            BIF_VALIDATE = 0x20
        }

        public class InitializedEventArgs : EventArgs
        {
            public readonly IntPtr hwnd;

            public InitializedEventArgs(IntPtr hwnd)
            {
                this.hwnd = hwnd;
            }
        }

        public delegate void InitializedHandler(ShellBrowseForFolderDialog sender, ShellBrowseForFolderDialog.InitializedEventArgs args);

        public class IUnknownEventArgs : EventArgs
        {
            public readonly IntPtr hwnd;
            public readonly IntPtr iunknown;

            public IUnknownEventArgs(IntPtr hwnd, IntPtr iunknown)
            {
                this.hwnd = hwnd;
                this.iunknown = iunknown;
            }
        }

        public delegate void IUnknownHandler(ShellBrowseForFolderDialog sender, ShellBrowseForFolderDialog.IUnknownEventArgs args);

        public enum RootTypeOptions
        {
            BySpecialFolder,
            ByPath
        }

        public class SelChangedEventArgs : EventArgs
        {
            public readonly IntPtr hwnd;
            public readonly IntPtr pidl;

            public SelChangedEventArgs(IntPtr hwnd, IntPtr pidl)
            {
                this.hwnd = hwnd;
                this.pidl = pidl;
            }
        }

        public delegate void SelChangedHandler(ShellBrowseForFolderDialog sender, ShellBrowseForFolderDialog.SelChangedEventArgs args);

        public class ValidateFailedEventArgs : EventArgs
        {
            public readonly IntPtr hwnd;
            public readonly string invalidSel;

            public ValidateFailedEventArgs(IntPtr hwnd, string invalidSel)
            {
                this.hwnd = hwnd;
                this.invalidSel = invalidSel;
            }
        }

        public delegate int ValidateFailedHandler(ShellBrowseForFolderDialog sender, ShellBrowseForFolderDialog.ValidateFailedEventArgs args);
    }
}

